import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CPUCycle implements Callable {
	public static String version = "1.0";
	private static long startTime = System.currentTimeMillis();

	private static void logSystemInfo() {
		double MB = 1024 * 1024;
		logMsg(System.getProperties().toString());
		logMsg("[JRE Version:: " + System.getProperty("java.runtime.version")
				+ " ]");
		logMsg("Runtime.getRuntime().availableProcessors() = "
				+ Runtime.getRuntime().availableProcessors()
				+ ", Runtime.getRuntime().maxMemory() = "
				+ Runtime.getRuntime().maxMemory() / (MB) + "[MB]");

	}

	private static void logKnownPerformanceNumbers() {

	}

	static ExecutorService exeSvc;

	public static <T> void runMultiThreadTest(int numberOfThreads)
			throws InterruptedException {

		int threadCount = numberOfThreads;

		if (numberOfThreads == 0) {
			threadCount = Runtime.getRuntime().availableProcessors();
		}
		exeSvc = Executors.newFixedThreadPool(threadCount);

		Collection<Callable> r = new ArrayList<Callable>();
		for (int i = 0; i < threadCount; i++) {
			r.add(new CPUCycle());
		}

		logMsg("Starting " + threadCount + " Threads");
		exeSvc.invokeAll((Collection<? extends Callable<T>>) r);
	}

	private static int howMany = 1000000000;

	private static void logMsg(String s) {
		System.out.println(String.format("%-30s %s", Thread.currentThread()
				.getName(), s));
	}

	public static void main(String args[]) throws InterruptedException {
		logSystemInfo();
		int numberOfThreads = 0; // Get from Runtime.availableProcessors()
		if (args != null && args.length >= 1) {
			try {
				howMany = Integer.valueOf(args[0]);

				if (args.length >= 2) {
					numberOfThreads = Integer.valueOf(args[1]);
				}
			} catch (Exception e) {
				System.err.println(args[0]
						+ " is not a valid number.  Using defaultValue = "
						+ howMany);
			}
		}

		runMultiThreadTest(numberOfThreads);

		long elapsedTime = System.currentTimeMillis() - startTime;
		logMsg("Overall elapsedTime = " + elapsedTime + " ms");
		exeSvc.shutdownNow();
	}

	@Override
	public Object call() throws Exception {
		long threadStartTime = System.currentTimeMillis();
		logMsg("Running loop " + howMany + " times");
		byte[] b = new byte[10];
		for (int i = 0; i < howMany; i++) {
			b[i % 10] = Integer.valueOf(i).byteValue();
		}
		long elapsedTime = System.currentTimeMillis() - threadStartTime;
		logMsg("[" + version + "] howMany = " + howMany + " elapsedTime = "
		        + elapsedTime + " ms");
		return elapsedTime;
	}
}
